package cn.bby.tools.utils;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTypesUtil;
import org.jetbrains.annotations.Nullable;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.intellij.psi.CommonClassNames.JAVA_UTIL_COLLECTION;

/**
 * @description: ClassDataMockUtil
 * @author: bby
 * @date: 2025/10/21 15:24
 * @version: 1.0
 */
public class ClassDataMockUtil {
    public static final String NOW = "Now";
    public static final String PAST = "Past";
    public static final String FUTURE = "Future";

    /**
     * 生成Mock数据
     */
    public static JSONObject generateMockData(PsiClass psiClass, boolean mockField) {
        return generateMockData(
                new GenMockParam(psiClass.getProject(), psiClass, mockField));
    }

    /**
     * 生成Mock数据
     *
     * @param genMockParam@return JSON字符串
     */
    public static JSONObject generateMockData(GenMockParam genMockParam) {
        // 创建一个新的Map来跟踪已处理的类，防止无限递归
        Map<String, JSONObject> processedClasses = new HashMap<>();
        return generateMockDataInternal(genMockParam, processedClasses);
    }

    /**
     * 生成Mock数据的内部实现
     *
     * @param processedClasses 已处理的类集合，防止无限递归
     * @return Mock数据Map
     */
    private static JSONObject generateMockDataInternal(GenMockParam genMockParam, Map<String, JSONObject> processedClasses) {
        // 添加当前类到已处理集合
        String classQualifiedName = genMockParam.psiClass.getQualifiedName();
        if (classQualifiedName == null || classQualifiedName.startsWith("java.")) {
            return new JSONObject();
        }
        if (processedClasses.containsKey(classQualifiedName)) {
            return processedClasses.get(classQualifiedName);
        }
        //防止循环依赖
        JSONObject mockData = new JSONObject();
        processedClasses.put(classQualifiedName, mockData);

        // 获取所有字段
        PsiField[] fields = genMockParam.psiClass.getFields();
        for (PsiField field : fields) {
            //排除静态与常量
            if (field.hasModifierProperty(PsiModifier.STATIC) || field.hasModifierProperty(PsiModifier.FINAL)) {
                continue;
            }
            String fieldName = field.getName();
            PsiType fieldType = field.getType();

            Object mockValue = generateFieldValueInternal(fieldType, genMockParam, processedClasses);
            mockData.set(fieldName, mockValue);
        }

        processedClasses.put(classQualifiedName, mockData);
        return mockData;
    }

    /**
     * 根据字段类型生成Mock值（内部实现）
     *
     * @param fieldType        字段类型
     * @param processedClasses 已处理的类集合，防止无限递归
     * @return Mock值
     */
    public static Object generateFieldValueInternal(PsiType fieldType, GenMockParam genMockParam
            , Map<String, JSONObject> processedClasses) {
        // 获取类型的标准名称
        String canonicalText = fieldType.getCanonicalText();

        if (!genMockParam.mock) {
            Object defaultValue = PsiTypesUtil.getDefaultValue(fieldType);
            if (defaultValue != null) {
                return defaultValue;
            }
            if (ClassChooseUtil.isCollType(genMockParam.project, fieldType)) {
                return generateMockCollection(fieldType, genMockParam, processedClasses);
            } else {
                if (canonicalText.startsWith("java.")) {
                    return getDefaultVal(fieldType);
                }
                //判断是否为复杂类
                return generateMockComplexType(fieldType, genMockParam, processedClasses);
            }
        }
        if (ClassChooseUtil.isCollType(genMockParam.project, fieldType)) {
            return generateMockCollection(fieldType, genMockParam, processedClasses);
        } else {
            if (canonicalText.startsWith("java.")) {
                // 基本类型处理
                return getValByCanonicalText(genMockParam, canonicalText);
            }
            return generateMockComplexType(fieldType, genMockParam, processedClasses);
        }
    }

    private static @Nullable Object getValByCanonicalText(GenMockParam genMockParam, String canonicalText) {
        return switch (canonicalText) {
            case "java.lang.String" -> generateMockString(genMockParam.stringDefaultValue, genMockParam.stringRandom);
            case "int", "java.lang.Integer" -> generateMockInt(genMockParam.intMinValue, genMockParam.intMaxValue);
            case "long", "java.lang.Long" -> generateMockLong(genMockParam.intMinValue, genMockParam.intMaxValue);
            case "boolean", "java.lang.Boolean" -> RandomUtil.randomBoolean();
            case "double", "java.lang.Double" -> generateMockDouble(genMockParam.intMinValue, genMockParam.intMaxValue);
            case "float", "java.lang.Float" -> generateMockFloat(genMockParam.intMinValue, genMockParam.intMaxValue);
            case "java.util.Date", "java.time.LocalDateTime", "java.time.LocalDate", "java.time.LocalTime" ->
                    generateMockTime(genMockParam.timeValue, genMockParam.timeFormat, genMockParam.timestamp);
            default -> null;
        };
    }

    private static Object generateMockCollection(PsiType fieldType, GenMockParam genMockParam, Map<String, JSONObject> processedClasses) {
        if (!genMockParam.nestedMock) {
            return Collections.emptyList();
        }

        PsiClass psiClass = ClassChooseUtil.findCollClass(genMockParam.project, fieldType);
        if (psiClass == null) {
            return Collections.emptyList();
        }
        String qualifiedName = psiClass.getQualifiedName();
        if (qualifiedName != null && qualifiedName.startsWith("java.")) {
            PsiClassType type = PsiTypesUtil.getClassType(psiClass);
            Object v = generateFieldValueInternal(type, genMockParam, processedClasses);
            return v == null ? Collections.emptyList() : List.of(v);
        }
        genMockParam.psiClass = psiClass;
        JSONObject objectMap = generateMockDataInternal(genMockParam, processedClasses);
        if (objectMap == null) {
            return Collections.emptyList();
        }
        return List.of(objectMap);
    }


    /**
     * 生成Mock字符串
     *
     * @param stringDefaultValue 字符串默认值
     * @param stringRandom       是否随机字符串
     * @return Mock字符串
     */
    private static String generateMockString(String stringDefaultValue, boolean stringRandom) {
        if (stringRandom) {
            // 根据默认值长度生成随机字符串
            int length = stringDefaultValue.length();
            if (length == 0) length = 5;
            return RandomUtil.randomString(length);
        } else {
            return stringDefaultValue;
        }
    }

    /**
     * 生成Mock整数
     *
     * @param intMinValue 最小整数值
     * @param intMaxValue 最大整数值
     * @return Mock整数
     */
    private static Integer generateMockInt(int intMinValue, int intMaxValue) {
        return RandomUtil.randomInt(intMinValue, intMaxValue);
    }

    /**
     * 生成Mock长整数
     *
     * @param intMinValue 最小整数值
     * @param intMaxValue 最大整数值
     * @return Mock长整数
     */
    private static Long generateMockLong(int intMinValue, int intMaxValue) {
        return (long) RandomUtil.randomInt(intMinValue, intMaxValue);
    }

    /**
     * 生成Mock双精度浮点数
     *
     * @param intMinValue 最小整数值
     * @param intMaxValue 最大整数值
     * @return Mock双精度浮点数
     */
    private static Double generateMockDouble(int intMinValue, int intMaxValue) {
        return RandomUtil.randomDouble(intMinValue, intMaxValue);
    }

    /**
     * 生成Mock单精度浮点数
     *
     * @param intMinValue 最小整数值
     * @param intMaxValue 最大整数值
     * @return Mock单精度浮点数
     */
    private static Float generateMockFloat(int intMinValue, int intMaxValue) {
        return (float) RandomUtil.randomDouble(intMinValue, intMaxValue);
    }

    /**
     * 生成Mock时间
     *
     * @param timeValue  时间值选项
     * @param timeFormat 时间格式
     * @param timestamp  是否使用时间戳
     * @return Mock时间
     */
    private static Object generateMockTime(String timeValue, String timeFormat, boolean timestamp) {
        LocalDateTime dateTime = switch (timeValue != null ? timeValue : PAST) {
            case NOW -> LocalDateTime.now();
            case FUTURE -> LocalDateTime.now().plusDays(RandomUtil.randomInt(1, 365));
            default -> LocalDateTime.now().minusDays(RandomUtil.randomInt(1, 365));
        };

        // 如果勾选了时间戳
        if (timestamp) {
            return dateTime.atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli();
        } else {
            // 使用指定格式
            try {
                return dateTime.format(DateTimeFormatter.ofPattern(timeFormat));
            } catch (Exception e) {
                return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
        }
    }

    /**
     * 生成Mock复杂类型
     *
     * @param fieldType        字段类型
     * @param processedClasses 已处理的类集合，防止无限递归
     * @return Mock值
     */
    private static Object generateMockComplexType(PsiType fieldType, GenMockParam genMockParam
            , Map<String, JSONObject> processedClasses) {
        // 检查是否已经处理过此类，防止无限递归
        if (!genMockParam.nestedMock) {
            return null;
        }
        if (fieldType.getCanonicalText().startsWith("java.")) {
            if (!genMockParam.mock) {
                return getDefaultVal(fieldType);
            }
            return generateFieldValueInternal(fieldType, genMockParam, processedClasses);
        }

        PsiClass psiClass = PsiTypesUtil.getPsiClass(fieldType);
        if (psiClass != null) {
            // 创建新的已处理类集合副本，防止并列字段互相影响
            genMockParam.psiClass = psiClass;
            return generateMockDataInternal(genMockParam, processedClasses);
        }
        // 默认返回null
        return null;
    }

    private static Object getDefaultVal(PsiType fieldType) {
        Object value = PsiTypesUtil.getDefaultValue(fieldType);
        if (value == null && fieldType.getCanonicalText().startsWith("java.lang.String")) {
            return "";
        }
        return value;
    }

    public static final class GenMockParam {
        public PsiClass psiClass;
        /// 项目实例
        public Project project;
        /// 字符串默认值
        public String stringDefaultValue;
        /// 是否随机字符串
        public boolean stringRandom;
        /// 最小整数值
        public int intMinValue;
        /// 最大整数值
        public int intMaxValue;
        /// 时间值选项
        public String timeValue;
        /// 时间格式
        public String timeFormat;
        /// 是否使用时间戳
        public boolean timestamp;
        /// 是否启用嵌套Mock
        public boolean nestedMock;
        /// 是否启用Mock
        public boolean mock;

        public GenMockParam(Project project, PsiClass psiClass, boolean mock) {
            this(project, psiClass, "test", true,
                    1, 100, PAST, "yyyy-MM-dd HH:mm:ss", false, true);
            this.mock = mock;
        }

        public GenMockParam(PsiClass psiClass, boolean mock) {
            this(psiClass.getProject(), psiClass, mock);
            this.mock = mock;
        }

        public GenMockParam(Project project, PsiClass psiClass, String stringDefaultValue,
                            boolean stringRandom, int intMinValue, int intMaxValue, String timeValue,
                            String timeFormat, boolean timestamp, boolean nestedMock) {
            this.psiClass = psiClass;
            this.project = project;
            this.stringDefaultValue = stringDefaultValue;
            this.stringRandom = stringRandom;
            this.intMinValue = intMinValue;
            this.intMaxValue = intMaxValue;
            this.timeValue = timeValue;
            this.timeFormat = timeFormat;
            this.timestamp = timestamp;
            this.nestedMock = nestedMock;
        }

    }
}